1 module hip.hipaudio.backend.xaudio.player; 2 3 version(Windows): 4 version(DirectX): 5 import hip.util.system:getWindowsErrorMessage; 6 import hip.hipaudio.backend.xaudio.source; 7 import hip.hipaudio.backend.xaudio.clip; 8 import hip.audio_decoding.audio; 9 import hip.error.handler; 10 import hip.hipaudio.audio; 11 import core.sys.windows.windef; 12 import directx.xaudio2; 13 14 extern(Windows) 15 { 16 // import core.sys.windows.objbase; //This would import all the uuid table. 17 enum COINIT { 18 COINIT_APARTMENTTHREADED = 2, 19 COINIT_MULTITHREADED = 0, 20 COINIT_DISABLE_OLE1DDE = 4, 21 COINIT_SPEED_OVER_MEMORY = 8 22 } 23 HRESULT CoInitialize(PVOID); 24 HRESULT CoInitializeEx(LPVOID, DWORD); 25 } 26 27 class HipXAudioPlayer : IHipAudioPlayer 28 { 29 IXAudio2 xAudio; 30 IXAudio2MasteringVoice masterVoice; 31 32 package immutable(AudioConfig) config; 33 34 /** 35 * For getting better debug information, you need to run this application on Visual Studio. 36 * The debug messages actually appears inside the `Output` window. 37 */ 38 public this(AudioConfig cfg) 39 { 40 this.config = cfg; 41 42 HRESULT hr; 43 version(UWP) 44 {} 45 else 46 { 47 CoInitializeEx(null, COINIT.COINIT_MULTITHREADED); 48 ErrorHandler.assertLazyExit(SUCCEEDED(hr), "CoInitializeEx error:\n\t"~HipXAudioPlayer.getError(hr)); 49 } 50 51 UINT32 flags; 52 version(HIPREME_DEBUG) 53 flags|= XAUDIO2_DEBUG_ENGINE; 54 55 hr = XAudio2Create(xAudio, flags, XAUDIO2_DEFAULT_PROCESSOR); 56 ErrorHandler.assertLazyExit(SUCCEEDED(hr), "XAudio2Create error:\n\t"~HipXAudioPlayer.getError(hr)); 57 58 59 hr = xAudio.CreateMasteringVoice(&masterVoice, cfg.channels, cfg.sampleRate, 0); 60 ErrorHandler.assertLazyExit(SUCCEEDED(hr), "CreateMasteringVoice error:\n\t"~HipXAudioPlayer.getError(hr)); 61 62 version(HIPREME_DEBUG) 63 { 64 XAUDIO2_DEBUG_CONFIGURATION debugConfig = XAUDIO2_DEBUG_CONFIGURATION( 65 XAUDIO2_LOG_ERRORS | XAUDIO2_LOG_WARNINGS, XAUDIO2_LOG_ERRORS, true, true, true, true 66 ); 67 xAudio.SetDebugConfiguration(&debugConfig); 68 } 69 } 70 71 public static string getError(HRESULT hr) 72 { 73 switch(hr) 74 { 75 case XAUDIO2_E_INVALID_CALL: return "XAUDIO2_E_INVALID_CALL: An API call or one of its arguments was illegal"; 76 case XAUDIO2_E_XMA_DECODER_ERROR: return "XAUDIO2_E_XMA_DECODER_ERROR: The XMA hardware suffered an unrecoverable error"; 77 case XAUDIO2_E_XAPO_CREATION_FAILED: return "XAUDIO2_E_XAPO_CREATION_FAILED: XAudio2 failed to initialize an XAPO effect"; 78 case XAUDIO2_E_DEVICE_INVALIDATED: return "XAUDIO2_E_DEVICE_INVALIDATED: An audio device became unusable (unplugged, etc)"; 79 default: return getWindowsErrorMessage(hr); 80 } 81 } 82 public bool play_streamed(AHipAudioSource src){return src.play_streamed();} 83 84 public AHipAudioSource getSource(bool isStreamed){return new HipXAudioSource(this);} 85 public IHipAudioClip getClip(){return new HipXAudioClip(new HipAudioDecoder(), HipAudioClipHint(2, 44_100, false, true));} 86 87 public IHipAudioClip loadStreamed(string audioName, uint chunkSize) 88 { 89 ErrorHandler.assertExit(false, "XAudio Player does not support chunked decoding"); 90 return null; 91 } 92 public void updateStream(AHipAudioSource source){} 93 94 public void onDestroy() 95 { 96 xAudio.Release(); 97 } 98 public void update(){} 99 }